﻿#include "OperatorsRemshFESubsystem.h"
#include "GUIDialog/GUISubSystemDialog/GUIFESubSystemRemeshDialog.h"
#include "GUIDialog/GUISubSystemDialog/GmshGenerateMeshDialog.h"

#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKGmshExeDriver/FITKGmshGeoScriptManuallyWrite.h"

#include "GUIFrame/MainWindow.h"
#include "GUIFrame/CentralWidget.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "PickDataProvider/PickedData.h"
#include "OperatorsInterface/GraphEventOperator.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMeshPartVTK.h"
#include "FITK_Component/FITK2DMeshTools/FITKAbstractSimplifyMesh.h"

#include <QDir>

namespace ModelOper
{

    bool OperatorsRemshFESubsystem::execGUI()
    {
        GUI::MainWindow * mainWindow = dynamic_cast<GUI::MainWindow *>(FITKAPP->getGlobalData()->getMainWindow());
        if (!mainWindow)return false;

        GUI::GUIFESubSystemRemeshDialog* dialog = new GUI::GUIFESubSystemRemeshDialog(this, mainWindow);
        connect(dialog, &QDialog::accepted, this, &OperatorsRemshFESubsystem::pickDataFinish);
        dialog->show();

        return false;
    }

    bool OperatorsRemshFESubsystem::execProfession()
    {
        //获取渲染器
        EventOper::GraphEventOperator* graphOper = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (graphOper == nullptr)return false;
        //渲染层显示数据
        int objID = 0;

        if (this->argValue("pickDataObjID", objID))
            graphOper->updateGraph(objID, true);
        //清除拾取模式和高亮
        GUI::GUIPickInfo::ClearPickInfo();
        return true;
    }

    void OperatorsRemshFESubsystem::pickDataFinish()
    {
        //获取主窗口
        GUI::MainWindow * mainWindow = dynamic_cast<GUI::MainWindow *>(FITKAPP->getGlobalData()->getMainWindow());
        if (!mainWindow)return;
        int objDataID = 0;
        if (!this->argValue<int>("pickDataObjID", objDataID)) return;
        //获取FE子系统
        Acoustics::FITKAcousticsDiscModel *discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel) return;
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        if (!feModel) return;
        Acoustics::FITKAcousticsFESubSysManager* subSysMgr = feModel->getFESubSysManager();
        if (!subSysMgr) return;
        Acoustics::FITKAbstractFESubSys* feSubsys = subSysMgr->getDataByID(objDataID);
        if (!feSubsys)return;
        // 获取维度
        int dim = feSubsys->getElementDim();
        if (dim == 1)
        {
            AppFrame::FITKMessageError("FE Sub-System does not exist face element !!! pick data Err !");
            return;
        }
        //生成脚本并进行网格划分
        Interface::FITKUnstructuredMesh meshObj;
        GUI::GmshGenerateMeshDialog dialog(this, mainWindow);
        dialog.setGenerateGeoThread(new GmshGeoScriptGenThread(this));
        dialog.setMeshData(&meshObj);
        dialog.startGmshMeshGen();
        dialog.exec();
        if (!feSubsys->updateMesh(&meshObj, dim)) return;
        feSubsys->updateGeoProp();
        this->execProfession();
    }


    GmshGeoScriptGenThread::GmshGeoScriptGenThread(Core::FITKActionOperator* oper) : _oper(oper)
    {
    }

    void GmshGeoScriptGenThread::run()
    {
        //获取类型
        if (!_oper) return;
        int objDataID = 0;
        if (!_oper->argValue<int>("pickDataObjID", objDataID)) return;
        //获取写出的脚本文件路径
        AppFrame::FITKAppSettings* settings = FITKAPP->getAppSettings();
        if (!settings) return;
        //获取工作目录
        QString workDir = settings->getWorkingDir();
        QDir dir(workDir);
        if (!dir.exists()) return;
        QString geoScriptFile = workDir + "/Gmsh/gmshFESubSystem.geo";
        //获取FE子系统
        Acoustics::FITKAcousticsDiscModel *discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel) return;
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        if (!feModel) return;
        Acoustics::FITKAcousticsFESubSysManager* subSysMgr = feModel->getFESubSysManager();
        if (!subSysMgr) return;
        Acoustics::FITKAbstractFESubSys* dataFEData = subSysMgr->getDataByID(objDataID);
        if (!dataFEData)return;
        // 获取类型
        Acoustics::FITKAbstractFESubSys::FESubSysType type = dataFEData->getFESubSysType();
        //写出脚本文件
        bool writeOk = false;
        if (type == Acoustics::FITKAbstractFESubSys::FESubSysType::FEStructure)
            writeOk = this->writeShellGeoScript(geoScriptFile, dataFEData);
        else if (type == Acoustics::FITKAbstractFESubSys::FESubSysType::FEAcoustic)
            writeOk = this->writeCavityGeoScript(geoScriptFile, dataFEData);
        //设置写出的参数
        _oper->setArgs("WriteOk", writeOk);
        _oper->setArgs("GeoFilePath", geoScriptFile);
    }

    bool GmshGeoScriptGenThread::writeShellGeoScript(QString geoScriptFile, Acoustics::FITKAbstractFESubSys* dataFEData)
    {
        if (!_oper || !dataFEData) return false;
        //获取节点和网格数据
        QList<int> nodesIDList = dataFEData->getNodesID();
        QList<int> elementsIDList = dataFEData->getElementsID();
        if (nodesIDList.isEmpty() || elementsIDList.isEmpty())return false;
        //获取划分尺寸和网格数量
        double meshSize = 0.0;
        int meshNumber = 0;
        bool isTri = false;
        bool isFixedBoundary = false;
        if (!_oper->argValue<double>("MeshSize", meshSize) || !_oper->argValue<int>("MeshNumber", meshNumber) || !_oper->argValue<bool>("IsTri", isTri) || !_oper->argValue<bool>("IsFixedBoundary", isFixedBoundary)) return false;
        //获取节点管理器 
        Acoustics::FITKAcousticsDiscModel *discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel) return false;
        Acoustics::FITKAcousticsDiscNodeList *discNodeList = discModel->getNodes();
        if (!discNodeList) return false;
        //获取单元管理器
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        if (!feModel) return false;
        Acoustics::FITKAcousticsFESubSysElementList* feElementList = feModel->getFESubSysElementList();
        if (!feElementList) return false;
        //存储点和单元
        QList<Core::FITKNode*> nodeList;
        QList<Interface::FITKElementTri3*> eleList;
        //获取节点数据
        for (int nID : nodesIDList)
        {
            Core::FITKNode *node = discNodeList->getNodeByID(nID);
            if (!node)continue;
            nodeList.append(node);
        }
        //获取单元数据
        for (int eID : elementsIDList)
        {
            Interface::FITKElementTri3* ele = dynamic_cast<Interface::FITKElementTri3*>(feElementList->getElementByID(eID));
            if (!ele) continue;
            eleList.append(ele);
        }
        int originalMeshNumber = eleList.size();
        //写出脚本
        GmshExe::FITKGmshGeoScriptManuallyWrite writeGeoScript;
        writeGeoScript.setFileName(geoScriptFile);
        //创建粗化网格工具
        Interface::FITKAbstractSimplifyMesh* simplifyMeshTool = Interface::FITKAbstractSimplifyMesh::createFITKSimplifyMesh();
        simplifyMeshTool->initPlateMesh(nodeList, eleList);
        //设置粗化参数配置
        simplifyMeshTool->lockVertices();
        if (isFixedBoundary)
            simplifyMeshTool->lockBoundary();
        //最长边比最短边
        simplifyMeshTool->setTriAspectRatio(10);
        //粗化到最少单元
        //获取粗化数量
        int simplifyMeshNum = 0;
        if (originalMeshNumber <= meshNumber)
            simplifyMeshNum = originalMeshNumber;
        else if (originalMeshNumber * 0.5 <= meshNumber)
            simplifyMeshNum = originalMeshNumber * 0.5;
        else if (originalMeshNumber * 0.1 <= meshNumber)
            simplifyMeshNum = originalMeshNumber * 0.1;
        else
            simplifyMeshNum = originalMeshNumber * 0.01;
        simplifyMeshTool->simplifyMesh(0, simplifyMeshNum);
        //写出点数据
        QList<Interface::FITKSimplifyMeshPoint> nodeData = simplifyMeshTool->getGeoPoint();
        for (QList<Interface::FITKSimplifyMeshPoint>::iterator iter = nodeData.begin(); iter != nodeData.end(); ++iter)
        {
            writeGeoScript.addPiont(iter->id, iter->coor);
        }
        //写出边数据
        QList<Interface::FITKSimplifyMeshEdge> edgeData = simplifyMeshTool->getGeoEdge();
        for (QList<Interface::FITKSimplifyMeshEdge>::iterator iter = edgeData.begin(); iter != edgeData.end(); ++iter)
        {
            writeGeoScript.addLine(iter->eid, iter->pid[0], iter->pid[1]);
        }
        //写出面数据
        QList<Interface::FITKSimplifyMeshFace> faceData = simplifyMeshTool->getGeoFace();
        QList<int> faceIDList{};
        for (QList<Interface::FITKSimplifyMeshFace>::iterator iter = faceData.begin(); iter != faceData.end(); ++iter)
        {
            writeGeoScript.addPlaneSurface(iter->fid, QList<int>() << iter->eid[0] << iter->eid[1] << iter->eid[2]);
            faceIDList.append(iter->fid);
        }
        //获取边界
        QList<int> edgeBoundaryIDList{};
        QList<Interface::FITKSimplifyMeshEdge> boundaryData = simplifyMeshTool->getGeoBoundary();
        for (QList<Interface::FITKSimplifyMeshEdge>::iterator iter = boundaryData.begin(); iter != boundaryData.end(); ++iter)
        {
            edgeBoundaryIDList.append(iter->eid);
        }

        writeGeoScript.addCompoundSurface(faceIDList);
        //不保留外边界
        //writeGeoScript.addCompoundCurve(edgeBoundaryIDList);
        if (!isTri)
            writeGeoScript.setSubdivisionAlgorithm(1);
        writeGeoScript.setMeshSize(meshSize, meshSize);
        writeGeoScript.setMeshGenerateDim(2);
        writeGeoScript.run();
        return true;
    }

    bool GmshGeoScriptGenThread::writeCavityGeoScript(QString geoScriptFile, Acoustics::FITKAbstractFESubSys* dataFEData)
    {
        return true;
    }


}

